﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Broadsides2d
{
    public class Port
    {
        private int x;
        private int y;
        private int portID=-1;

        private Random rand = new Random();
        private int tradeshipCost = 250;
        private int attackshipCost = 500;
        private const int TURNCOOLDOWN = 200;
        private int turn;
        private int gold = 0;

        private int cooldown;
        private int cannonCooldown;
        private const int range = 200;

        Port[] tradePorts;
        List<TradeNPC>[] tradeShips;
        public List<Tile>[] routes;

        public Port(int x, int y)
        {
            this.x = x;
            this.y = y;
            cooldown = cannonCooldown = 140;
        }

        public void Update()
        {
            gold++;
            turn++;

            if (turn > TURNCOOLDOWN)
            {
                turn = 0;
                switch (rand.Next(2))
                {
                    case 0: trade();
                        break;
                    case 1: attack();
                        break;
                }
            }

            defend();
        }

        private void defend()
        {
            
            if(cooldown > 0)
                cooldown--;

            float diffX = 0f;
            float diffY = 0f;
            foreach (Player p in Game1.players)
            {
                if (cooldown == 0)
                {
                    diffX =  p.getX() - x*8;
                    diffY =  y*8 - p.getY();
                    if (Math.Sqrt((diffX * diffX) + (diffY * diffY)) <= range)
                    {
                        fireCannon((float)Math.Atan2(diffX, diffY));
                    }
                }
            }
        }
         
        private void fireCannon( float rotation)
        {
            Game1.cannonballs.Add(new Cannonball((float)x*8, (float)y*8, rotation, 60, 20, this));
            
            cooldown = cannonCooldown;
                
        }



        public void trade()
        {
            
            if (gold > tradeshipCost)
            {
                gold -= tradeshipCost;

                int r;
                do
                {
                    r = rand.Next(tradePorts.Length);
                }
                while (r == this.portID);


                Game1.npcShips.Add(new TradeNPC(this.x * Tile.SIZE, this.y * Tile.SIZE, tradePorts[r], tradeshipCost, this));
                    
            }
        }

        public void attack()
        {

            if (gold > attackshipCost)
            {
                gold -= attackshipCost;

                int r;
                do
                {
                    r = rand.Next(tradePorts.Length);
                }
                while (r == this.portID);


                Game1.npcShips.Add(new AttackNPC(this.x * Tile.SIZE, this.y * Tile.SIZE, tradePorts[r], 25, this));

            }
        }

        public void traded()
        {
            gold += tradeshipCost * 2;
        }

        public static void connectPorts(Port[] ports)
        {
            int id = 0;
            foreach (Port p in ports)
            {
                p.portID = id++;
                p.tradePorts = new Port[ports.Length];
                p.tradeShips = new List<TradeNPC>[ports.Length];
                p.routes = new List<Tile>[ports.Length];

                //foreach(p.routes())
            }

            foreach (Port p in ports)
            {
                for (int i = 0; i < ports.Length; i++)
                {
                    Port o = ports[i];

                    if (p.portID == i)
                        continue;

                    p.tradePorts[i] = o;

                    List<TradeNPC> tradeList = new List<TradeNPC>();
                    p.tradeShips[i] = tradeList;
                    o.tradeShips[p.portID] = tradeList;

                        
                    List<Tile> route = formRoute(p,o);
                    route.Reverse();
                    p.routes[i] = route;
                  
                }
            }
        }

        private static bool[,] tilesToCheck;
        private static List<Tile> formRoute(Port from, Port to)
        {
            tilesToCheck = new bool[World.world.worldSize, World.world.worldSize];
            List<Tile> re = formRoute( from.getX(), from.getY(), to.getX(), to.getY());

            if(re == null)
              re = formRoute(from.getX(), from.getY()-1, to.getX(), to.getY());

            if (re == null)
                re = formRoute(from.getX(), from.getY() + 1, to.getX(), to.getY());

            if (re == null)
                re = formRoute(from.getX() - 1, from.getY() - 1, to.getX(), to.getY());


            if (re == null)
                re = formRoute(from.getX() - 1, from.getY() + 1, to.getX(), to.getY());

            if (re == null)
                re = formRoute(from.getX() - 1, from.getY() , to.getX(), to.getY());

            if (re == null)
                re = formRoute(from.getX() + 1, from.getY() - 1, to.getX(), to.getY());

            if (re == null)
                re = formRoute(from.getX() + 1, from.getY() + 1, to.getX(), to.getY());

            if (re == null)
                re = formRoute(from.getX() + 1, from.getY(), to.getX(), to.getY());


            return re;
        }

        
        private static List<Tile> formRoute( int fx, int fy, int tx, int ty)
        {
            fx = (fx + World.world.worldSize) % World.world.worldSize;
            fy = (fy + World.world.worldSize) % World.world.worldSize;
            if(tilesToCheck[fx, fy])
                return null;

            tilesToCheck[fx, fy] = true;

            if (fx == tx && fy == ty)
                return new List<Tile>();

            int dx = fx == tx ? 0 : (fx > tx ? -1 : 1);
            dx = tx - fx > World.world.worldSize / 2 ? -dx : dx;
            int dy = fy == ty ? 0 : (fy > ty ? -1 : 1);
            dy = ty - fy > World.world.worldSize / 2 ? -dy : dy;

            int towardsX = (fx + dx + World.world.worldSize) % World.world.worldSize;
            int towardsY = (fy + dy + World.world.worldSize) % World.world.worldSize;


            int tyn1 = (towardsY - 1 + World.world.worldSize) % World.world.worldSize;
            int txn1 = (towardsX - 1 + World.world.worldSize) % World.world.worldSize;
            int tx1 = (towardsX + 1 + World.world.worldSize) % World.world.worldSize;
            int ty1 = (towardsY + 1 + World.world.worldSize) % World.world.worldSize;


            if (World.world.tiles[txn1, tyn1].getType() != Tile.TileType.land &&
                World.world.tiles[txn1, towardsY].getType() != Tile.TileType.land &&
                World.world.tiles[txn1, ty1].getType() != Tile.TileType.land &&
                World.world.tiles[towardsX, tyn1].getType() != Tile.TileType.land &&
                World.world.tiles[towardsX, towardsY].getType() != Tile.TileType.land &&
                World.world.tiles[towardsX, ty1].getType() != Tile.TileType.land &&
                World.world.tiles[tx1, tyn1].getType() != Tile.TileType.land &&
                World.world.tiles[tx1, towardsY].getType() != Tile.TileType.land &&
                World.world.tiles[tx1, ty1].getType() != Tile.TileType.land)
            {
            //if(World.world.tiles[towardsX, towardsY].getType() != Tile.TileType.land){
                List<Tile> re = null;
                
                re = formRoute(towardsX, towardsY, tx, ty);


                if(re == null)
                    re = formRoute(fx, towardsY, tx, ty);

                if(re == null)
                    re = formRoute(towardsX, fy, tx, ty);

                if (re == null)
                    re = formRoute(fx-1, towardsY, tx, ty);

                if (re == null)
                    re = formRoute(towardsX, fy+1, tx, ty);

                if (re == null)
                    re = formRoute(fx + 1, towardsY, tx, ty);

                if (re == null)
                    re = formRoute(towardsX, fy - 1, tx, ty);

                if (re == null)
                    re = formRoute(fx - 1, fy - 1, tx, ty);

                if (re == null)
                    re = formRoute(fx + 1, fy - 1, tx, ty);

                if (re == null)
                    re = formRoute(fx + 1, fy + 1, tx, ty);

                if (re == null)
                    re = formRoute(fx + 1, fy + 1, tx, ty);

                if (re != null)
                {
                    re.Add(World.world.tiles[towardsX, towardsY]);
                    return re;
                }
            }

            return null;
        }


        public int getX()
        {
            return x;
        }

        public int getY()
        {
            return y;
        }

        public int getPixelX()
        {
            return x * Tile.SIZE;
        }

        public int getPortId()
        {
            return portID; 
        }

        public int getPixelY()
        {
            return y * Tile.SIZE;
        }
    }
}
